
#include "gm_stream_mgr.h"
#include <memory.h>
#include <stdlib.h>
#include <string.h>
#ifndef NULL
#define NULL 0
#endif



gm_stream_mgr::gm_stream_mgr(void)
{
	_pHeader = NULL;
	_pEndle = NULL;
	_pRemainData = NULL;
	_block_size = 0;
	_ulTotallen = 0;
	_max_apdu_len = get_max_transmit_len();
}

gm_stream_mgr::~gm_stream_mgr(void)
{
	if(_pRemainData)
	{
		free(_pRemainData);
		_pRemainData = NULL;
	}
}

BYTE *gm_stream_mgr::init(ULONG totalLen, int blockSize)
{
	_ulTotallen = totalLen;
	if(_pRemainData)
		free(_pRemainData);

	_pRemainData = (unsigned char*)malloc(_ulTotallen);
	memset(_pRemainData, 0, _ulTotallen);

	_block_size = blockSize;
	_pHeader = _pEndle = _pRemainData;

	return _pRemainData;
}

long gm_stream_mgr::increase( long size )
{
	long newSize = size + _max_apdu_len;
	long remain_len = _pEndle-_pHeader;

	unsigned char * pNewBase = (unsigned char*)malloc(newSize);
	memset(pNewBase, 0 , newSize);

	memcpy(pNewBase, _pHeader, remain_len);

	free(_pRemainData);

	_pRemainData = pNewBase;
	_pHeader = _pRemainData;
	_pEndle = _pRemainData + remain_len;
	
	_ulTotallen = newSize;
	return 0;
}

BYTE *gm_stream_mgr::push_data(BYTE *pbData, ULONG ndatalen)
{
	long newSize = ndatalen + (_pEndle - _pHeader);
	if(newSize > _ulTotallen)
	{
		increase(newSize);
	}

	memcpy(_pEndle, pbData, ndatalen);
	_pEndle += ndatalen;
	return _pHeader;
}

BYTE *gm_stream_mgr::pop_data(int nlen/* = 0*/)
{
	long data_len =  _pEndle - _pHeader;
	if(nlen <= data_len)
	{
		memmove(_pHeader, _pHeader + nlen, data_len - nlen);
		_pEndle -= nlen;
	}
	
	return _pHeader;
}

ULONG gm_stream_mgr::get_data_len()
{
	return _pEndle - _pHeader;
}

BYTE * gm_stream_mgr::get_data_ptr()
{
	return _pHeader;
}



void gm_stream_mgr::release()
{
	if(_pRemainData)
	{
		free(_pRemainData);
		_pRemainData = NULL;
	}
}

void gm_stream_mgr::set_max_apdu_len( ULONG maxLen )
{
	_max_apdu_len = maxLen;
}

ULONG gm_stream_mgr::get_block_data_len()
{
	ULONG data_len = get_data_len();

	if(_block_size == 0)
		return 0;

	if(data_len < _block_size)
		return 0;

	if(data_len >= _max_apdu_len)
	{
		return _max_apdu_len;
	}
	
	return _block_size * (data_len / _block_size);
}

